package com.jf3q.iot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jf3q.iot.domain.IotDevice;
import com.jf3q.iot.domain.IotElectricityUse;
import com.jf3q.iot.domain.IotGateway;
import com.jf3q.iot.mapper.IotDeviceMapper;
import com.jf3q.iot.mapper.IotElectricityUseMapper;
import com.jf3q.iot.mapper.IotGatewayMapper;
import com.jf3q.iot.netty.NettyServerHandler;
import com.jf3q.iot.service.SendInstructsService;
import com.jf3q.iot.utils.ElectricityMeterUtil;
import com.jf3q.iot.utils.InstructConstant;
import com.jf3q.iot.utils.InstructTypeConstant;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

/**
 * @author:xiaojie
 * @create: 2023-06-01 09:20
 * @Description:
 */
@Service("sendInstructsService")
@Slf4j
public class SendInstructsServiceImpl implements SendInstructsService {

    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    IotDeviceMapper deviceMapper;
    @Resource
    IotGatewayMapper gatewayMapper;
    @Resource
    IotElectricityUseMapper billElectricityUseDao;
    @Override
    public void sendInstructs(String instruce, String ip,String deviceCode,String operationType) {
        //防止一台设备同时下发多条指令，如果缓存中有记录则表示上次的操作还未完成
        String type = stringRedisTemplate.opsForValue().get(InstructConstant.handleInstructs + deviceCode);
        if(StringUtils.isEmpty(type)){
            stringRedisTemplate.opsForValue().set(InstructConstant.handleInstructs+deviceCode, operationType,30, TimeUnit.SECONDS);
            ChannelGroup channelGroup= NettyServerHandler.getChannelGroup();
            Iterator channelIterator =  channelGroup.iterator();
            while(channelIterator.hasNext()){
               Channel channel = (Channel)channelIterator.next();
                    InetSocketAddress insocket = (InetSocketAddress)channel.remoteAddress();
                    //给指定客户端ip发送消息
                    if(ip.equals(insocket.toString())){
                        channel.writeAndFlush(instruce);
                        channel.flush();
                    }
                }

            }


        //保存操作记录——在增强类里写（面向切面编程）



    }

    @Override
    public void callbackInstructResultMsg(String returnStr) {
        //回调处理
        if(StringUtils.isEmpty(returnStr) || !returnStr.startsWith("FE")){
            return;
        }
        //获取回调设备编号要有好几步骤
        String notFEStr = returnStr.substring(returnStr.indexOf("68")+2);
        String deviceType = notFEStr.startsWith("10")?"w":"e";
        //根据设备号找到数据，并更新数据
        if("e".equals(deviceType)) {//e就是电表  w就是水表

            String addressNo = notFEStr.substring(0,notFEStr.indexOf("68"));
            //获取设备号
            String deviceNo = ElectricityMeterUtil.addressConvertNo(addressNo,true);
            //获取操作类型
            String operationType = stringRedisTemplate.opsForValue().get(InstructConstant.handleInstructs+deviceNo);
            //删除redis中的数据
            stringRedisTemplate.delete(InstructConstant.handleInstructs+deviceNo);
            //电表操作
            handleOperation(deviceNo,operationType,notFEStr);

        }
    }

    private void handleOperation(String deviceNo, String operationType, String notFEStr) {


        LambdaQueryWrapper<IotDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(IotDevice::getDeviceCode,deviceNo);
        IotDevice device = deviceMapper.selectOne(wrapper);
        //合总电闸，拉闸或合闸后修改设备表状态
        if(InstructTypeConstant.E_MAIN_GATE_NO.getKey().equals(operationType)){
            device.setElectricityStatus(1);
            deviceMapper.update(device,wrapper);
        }
        //拉总电闸
        if(InstructTypeConstant.E_MAIN_GATE_OFF.getKey().equals(operationType)){
            device.setElectricityStatus(0);
            deviceMapper.update(device,wrapper);
        }
        /*//合A路电闸
        if(InstructTypeConstant.E_A_GATE_NO.getKey().equals(operationType)){
            device.setElectricityAStatus("1");
            deviceMapper.update(vo,wrapper);
        }
        //拉A路电闸
        if(InstructTypeConstant.E_A_GATE_OFF.getKey().equals(operationType)){
            vo.setElectricityAStatus("0");
            iotDeviceDao.update(vo,wrapper);
        }
        //合B路电闸
        if(InstructTypeConstant.E_B_GATE_NO.getKey().equals(operationType)){
            vo.setElectricityBStatus("1");
            iotDeviceDao.update(vo,wrapper);
        }
        //拉B路电闸
        if(InstructTypeConstant.E_B_GATE_OFF.getKey().equals(operationType)){
            vo.setElectricityBStatus("0");
            iotDeviceDao.update(vo,wrapper);
        }*/

        //获取电表费控数据
        if(InstructTypeConstant.E_BALANCE_SETUPA.getKey().equals(operationType)){
            getElectricityBalanceInfo(notFEStr,deviceNo);
        }

    }

    private void getElectricityBalanceInfo(String notFEStr, String deviceNo) {

        String dataStr = notFEStr.substring(notFEStr.indexOf("81104A1C")+8,notFEStr.length()-4);
        //剩余金额
        String surplusAmount = dataStr.substring(12,20);
        surplusAmount = ElectricityMeterUtil.deviceAddressConvert(surplusAmount);
        surplusAmount = ElectricityMeterUtil.dataAreaSubtract33(surplusAmount);
        log.info("getElectricityBalanceInfo surplusAmount {} {}",surplusAmount);
        int amount = Integer.parseInt(surplusAmount.replaceAll(" ",""),16);
        log.info("getElectricityBalanceInfo amount {} {}",amount);
        String surplusAmountStr = String.valueOf(amount*0.01);
        log.info("getElectricityBalanceInfo surplusAmount {} {}",surplusAmount,surplusAmountStr);

        //查询设备信息
        LambdaQueryWrapper<IotDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(IotDevice::getDeviceCode,deviceNo);
        IotDevice vo = deviceMapper.selectOne(wrapper);
        BigDecimal deviceBalance = vo.getDeviceBalance();//抄表前的剩余金额
        BigDecimal deviceSurplus = vo.getDeviceSurplus();//抄表前的剩余电量
        //计算使用费用
        BigDecimal useBalance = deviceBalance.subtract(new BigDecimal(surplusAmountStr));
        log.info("Electricity balance: {}",useBalance);
        //计算使用量
        BigDecimal useSurplus = useBalance.divide(new BigDecimal(1));//电的单价  一块 divide是除以
        //计算设备剩余费用
        BigDecimal remnantBalance = deviceBalance.subtract(useBalance);//现在的余额
        BigDecimal remnantQuantity = deviceSurplus.subtract(useSurplus);//现在的电量
        IotElectricityUse billElectricityUse = new IotElectricityUse();
        billElectricityUse.setDeviceId(vo.getId());
        billElectricityUse.setBeforUseBalance(deviceBalance);
        billElectricityUse.setBeforUseElectricity(deviceSurplus);
        //账户余额与电表余额对比
        if(deviceBalance.compareTo(new BigDecimal(surplusAmountStr))>0){
            //使用过电，修改余额和可使用量
            vo.setDeviceBalance(remnantBalance);
            vo.setDeviceSurplus(remnantQuantity);
            //更新设备金额
            deviceMapper.updateById(vo);
            //添加抄表记录
            billElectricityUse.setUseElectricity(useSurplus);
            billElectricityUse.setUseCost(useBalance);
            billElectricityUseDao.insert(billElectricityUse);
        }else{
            //没有使用过电 添加抄表记录
            billElectricityUse.setUseElectricity(BigDecimal.ZERO);
            billElectricityUse.setUseCost(BigDecimal.ZERO);
            billElectricityUseDao.insert(billElectricityUse);
        }

        //结算余额小于0，拉闸停电
        if(deviceBalance.compareTo(BigDecimal.ZERO)<0 || remnantBalance.compareTo(BigDecimal.ZERO)<0){
            log.info("Electricity Balance Not enough");
            IotGateway gatewayVO = gatewayMapper.selectById(vo.getGatewayId());
            String address = ElectricityMeterUtil.deviceAddressConvert(deviceNo);
            String newIp = "/"+gatewayVO.getGatewayIp()+":"+gatewayVO.getGatewayPort();
            String instructs = ElectricityMeterUtil.getCompleteInstruct(address,InstructConstant.ELECTRICITY_METER_PULL_INSTRUCT);
            //获取发送指令
            sendInstructs(instructs,newIp,deviceNo,InstructTypeConstant.E_MAIN_GATE_OFF.getKey());
            log.info("Electricity Balance sendInstructs success");
            //修改总闸状态
            vo.setElectricityStatus(0);
            deviceMapper.updateById(vo);
        }else{
            //余额大于0，合闸送电
            log.info("Electricity Balance enough");
            IotGateway gatewayVO = gatewayMapper.selectById(vo.getGatewayId());
            String address = ElectricityMeterUtil.deviceAddressConvert(deviceNo);
            String newIp = "/"+gatewayVO.getGatewayIp()+":"+gatewayVO.getGatewayPort();
            String instructs = ElectricityMeterUtil.getCompleteInstruct(address,InstructConstant.ELECTRICITY_METER_ON_INSTRUCT);
            //获取发送指令
            sendInstructs(instructs,newIp,deviceNo,InstructTypeConstant.E_MAIN_GATE_NO.getKey());
            log.info("Electricity Balance sendInstructs success");
            //修改总闸状态
            vo.setElectricityStatus(1);
            deviceMapper.updateById(vo);
        }
    }

    /**
     * 数据转换
     * @param aVoltage 元数据
     * @param precisionIndex 几位小数
     * @return
     */
    private static String dataChange(String aVoltage,int precisionIndex){
        String dataBCD = ElectricityMeterUtil.hexAddcharacter(aVoltage," ");
        String subtract33Data =  ElectricityMeterUtil.dataAreaSubtract33(dataBCD);
        log.info("dataChange {}",subtract33Data);
        String changeAfterStr = ElectricityMeterUtil.addressConvertNo(subtract33Data,false);
        Long changeAfterLong = Long.valueOf(changeAfterStr);
        if(precisionIndex==1){
            return String.valueOf(changeAfterLong*0.1);
        }
        if(precisionIndex==2){
            return String.valueOf(changeAfterLong*0.01);
        }
        if(precisionIndex==3){
            return String.valueOf(changeAfterLong*0.001);
        }
        if(precisionIndex==4){
            return String.valueOf(changeAfterLong*0.0001);
        }
        return String.valueOf(changeAfterLong);
    }

}
